/****************************************************************************
** Copyright (c) OpenFixFAST  All rights reserved.
**
** This file is part of the OpenFixFAST and QuickFIX FIX Engine
**
** This file may be distributed under the terms of the quickfixengine.org
** license as defined by quickfixengine.org and appearing in the file
** LICENSE included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.quickfixengine.org/LICENSE for licensing information.
** See http://www.openfixfast.com/LICENSE for licensing information.
**
** Contact ask@quickfixengine.org/openfixfast@gmail.com if any conditions of this licensing are
** not clear to you.
**
****************************************************************************/

#ifdef _MSC_VER
#include "stdafx.h"
#else
#include "config.h"
#endif
#include "CallStack.h"

#include "FASTParser.h"
#include "Message.h"
#include "Utility.h"
#include "FieldConvertors.h"
#include <algorithm>

namespace FIX {
	bool FASTParser::extractLength(int& length, std::string::size_type& pos,
		const std::string& buffer) throw (MessageParseError) {
			QF_STACK_PUSH(FASTParser::extractLength)

				if (!buffer.size())
					return false;

			std::string::size_type startPos = buffer.find("\0019=", 0);
			if (startPos == std::string::npos)
				return false;
			startPos += 3;
			std::string::size_type endPos = buffer.find("\001", startPos);
			if (endPos == std::string::npos)
				return false;

			std::string strLength(buffer, startPos, endPos - startPos);

			try {
				length = IntConvertor::convert(strLength);
				if (length < 0)
					throw MessageParseError();
			} catch (FieldConvertError&) {
				throw MessageParseError();
			}

			pos = endPos + 1;
			return true;

			QF_STACK_POP}

	void FASTParser::decodeTags( int tid, std::stringstream & ss, std::string msg_type )
	{

		static u32 globalSeqNum = 0;
		FastTagVector tags = m_dataDictionary->getFieldTag( tid );
		u32 u32Value = 0;
		i32 i32Value = 0;
		double doubleValue = 0;
		i64 i64Value = 0;
		u64 u64Value = 0;
		u8 charValue[MAX_STR_LEN];
		static u32 decimalCount = 0;
		FastTagVector::iterator itr = tags.begin();
		FastTagVector::iterator itrend = tags.end();

		for ( ; itr != itrend; ++itr )
		{
			memset(charValue, '\0', sizeof(charValue));
			switch( itr->m_type )
			{
			case eFAST_TYPE_ASCII:
				if ( iFast.decode_string (itr->m_tag, STR_ARGS (charValue)) > 0 )
				{
					ss << itr->m_num << "=" << charValue << "\001";
				}
				break;
			case eFAST_TYPE_I32:
				if ( iFast.decode_i32 (itr->m_tag, &i32Value) > 0 )
				{
					ss << itr->m_num << "=" << i32Value << "\001";
				}
				break;
			case eFAST_TYPE_U32:
				if ( iFast.decode_u32 (itr->m_tag, &u32Value) > 0 )
				{
					ss << itr->m_num << "=" << u32Value << "\001";
				}
				break;
			case eFAST_TYPE_GROUP:
				if( iFast.decode_group_count (itr->m_tag, &u32Value) > 0 )
				{
					ss << itr->m_num << "=" << u32Value << "\001";
					for (unsigned int i = 0; i < u32Value; i++ )
					{
						FASTPMap tmap;
						if ( itr->get_pmap_req() )
						{
							iFast.backup_presence_map(tmap);
							iFast.reset_presence_map();
							if (iFast.decode_message (eFAST_BASE_TID) < 0)
								return;
						}
						u32 templateID = 0;
						//a.decodeMsgLen (eFAST_MSG_TYPE, templateID); 
						//simulate eFAST_MSG_TYPE
						if ( itr->get_ref_tid() == "none" )
							templateID = atoi(itr->get_ref_tid().c_str());
						else
						{
							int iRefId = atoi(itr->get_ref_tid().c_str());
							if ( iRefId & 0x2000) //No templateId Present
							{
								templateID = iRefId;
								decodeTags( templateID, ss );
							}
							else
							{
								iFast.decode_u32 (eFAST_MSG_TYPE, &templateID);
								if ( templateID != (unsigned int)atoi(itr->get_ref_tid().c_str()) )
									throw "Template not found:";
								decodeTags( itr->get_num(), ss );
							}

						}
						if ( itr->get_pmap_req() )
						{
							iFast.reset_presence_map();
							iFast.restore_presence_map(tmap);
						}
					}
				}
				break;
			case eFAST_TYPE_DECMIAL:
				if ( itr->m_num == 451)
				{
					decimalCount++;
				}
				if( iFast.decode_double(itr->m_tag, &doubleValue) > 0 )
				{
					ss << itr->m_num << "=" << doubleValue << "\001";
				}
				break;
			case eFAST_TYPE_UNICODE:
				if ( iFast.decode_string (itr->m_tag, STR_ARGS (charValue)) > 0 )
				{
					ss << itr->m_num << "=" << charValue << "\001";
				}
				break;
			case eFAST_TYPE_I64:
				if ( iFast.decode_i64 (itr->m_tag, &i64Value) > 0 )
				{
					ss << itr->m_num << "=" << i64Value << "\001";
				}
				break;
			case eFAST_TYPE_U64:
				if ( iFast.decode_u64 (itr->m_tag, &u64Value) > 0 )
				{
					ss << itr->m_num << "=" << u64Value << "\001";
				}
				break;
			default:
				break;
			}
			if ( itr->m_num == 451 == 34 )
			{
				if ( /*globalSeqNum +1 !=*/ u32Value > 18700271 )
				{
					//std::cout << "Missing in core:" << (*(itr)._Myptr).m_num << ":" << u32Value- globalSeqNum << std::endl;
				}
				globalSeqNum = u32Value;
			}

		}
	}

	bool FASTParser::readMessage( std::string& str )
		throw( MessageParseError )
	{QF_STACK_PUSH(FASTParser::readMessage)

	try

	{

		std::string msg_type;

		if ( m_parser_iq.empty() )
		{
			if( !m_iq.empty() ) 
			{
				LockerTry l( m_iq_mutex );
				if ( l.isLocked() ) 
				{
					std::swap(m_parser_iq, m_iq );
				}
			}
			if (m_parser_iq.empty()) return false;
		}

		const iMsg& msg = m_parser_iq.front();
		iFast.set_codec_input(const_cast<u8*>(msg.c_ustr()), msg.length() );


		iFast.reset_presence_map();

		if (iFast.decode_message (eFAST_BASE_TID) < 0)
			return false;

		u32 tid = 0;
		iFast.decode_u32 (eFAST_MSG_TYPE, &tid); //put it back once corrected in the back-end

		reset(tid);

		TemplateId2Msg::iterator ii = m_TemplateId2Message->find(tid);
		if ( ii == m_TemplateId2Message->end())
			throw "Error, please define tid";

		msg_type = ii->second;
		std::stringstream ss;
		//Hello & Alert Message
		if ( tid != 16002 && tid != 16003) 
		{
			//decodeTags( eFAST_HDR_TEMPLATE, ss, msg_type );
		}

		//Body part
		decodeTags(tid, ss, msg_type);

		//Hello & Alert Message
		if ( tid != 16002 && tid != 16003) 
		{
			//decodeTags(eFAST_TRL_TEMPLATE, ss, msg_type);
		}

		if (iFast.decode_message_end (eFAST_BASE_TID) < 0)
			return false;
		ss << 10 << "=" << 9999 << "\001" << 56 << "=" << "FIX_USER" << "\001";
		std::stringstream lengthStr;
		lengthStr << ss.str().length();
		str = std::string("8=FIXT.1.1\001") + std::string("9=") + lengthStr.str() + std::string("\001") + ss.str() ;
		m_parser_iq.pop_front();
		m_msgCount--;
	}
	catch(...)
	{
		int p = 0;
	}
	return true;

	QF_STACK_POP

	}


	
	static THREAD_PROC startSocketThread(void *p)
	{
		try
		{
			SocketThreadData* pSocketThreadData = static_cast<SocketThreadData*>(p);

			int size = 1;
			socklen_t addrlen = sizeof(pSocketThreadData->m_addr);
			struct timeval timeout = { 0, 0 };
			while( pSocketThreadData->m_parser.m_Run )
			{
				fd_set readSet;
				timeout.tv_sec = 0;
				timeout.tv_usec = 2;
				FD_ZERO( &readSet );
				FD_SET( pSocketThreadData->m_socket, &readSet );
				int result = select( FD_SETSIZE, &readSet, NULL, NULL, &timeout );

				if(!pSocketThreadData->m_local_iq.empty())
				{
					if ( pSocketThreadData->m_parser.m_iq.empty() )
					{
						LockerTry l( pSocketThreadData->m_parser.m_iq_mutex );
						if ( l.isLocked() ) 
						{
							std::swap(pSocketThreadData->m_parser.m_iq, pSocketThreadData->m_local_iq);
						}
					}
				}
				if ( result == 0 )
				{
					continue;
				}
				size = recvfrom( pSocketThreadData->m_socket, pSocketThreadData->m_sockbuffer, sizeof(pSocketThreadData->m_sockbuffer), 0, (struct sockaddr*)&pSocketThreadData->m_addr, &addrlen );
				//printf("[%s]Received from %s on UDP port %d (port at sender is %d): \n%s[%d]\n", FIX::TransactTime(true).getString().c_str(), inet_ntoa(pSocketThreadData->m_addr.sin_addr), pSocketThreadData->m_addr.sin_port, ntohs(pSocketThreadData->m_addr.sin_port), pSocketThreadData->m_sockbuffer, size);

				if ( size <= 5 )
				{
					if ( size < 0 )
					{
						if ( size == 0 ) continue;
						throw SocketRecvFailed( size );
					}
					else
					{
						continue;
					}

				}

				//
				static char m_size[6] = {0};
				static unsigned int msgCount = 0;
				static unsigned int msgCountSize = 0;
				msgCountSize += size;

				memset(m_size, 0,6);
				memcpy(m_size, pSocketThreadData->m_sockbuffer,5);
				int newCount = atoi(m_size);
				if ( newCount - msgCount > 1)
				{
					std::cout << "Hard Limit :" << (newCount - msgCount) << "!" << newCount << " - " << msgCount << std::endl;	
				}
				msgCount = newCount;
				size -= 5;

				pSocketThreadData->m_local_iq.push_back(FIX::Parser::iMsg(pSocketThreadData->m_sockbuffer+5, size)); //as per CME

				pSocketThreadData->m_parser.m_msgCount++;

				if (pSocketThreadData->m_parser.getSocketLogFile().good())
				{

					pSocketThreadData->m_parser.getSocketLogFile().write((const char*)&size, sizeof(size));
					pSocketThreadData->m_parser.getSocketLogFile().write(pSocketThreadData->m_sockbuffer+5, size);
				}
			}
		}
		catch ( std::exception & e )
		{
			std::cout << e.what();
		}
		return 0;
	}

	
	void FASTParser::readFromStream( int socket, sockaddr_in &addr) throw ( SocketRecvFailed )
	{QF_STACK_PUSH(FASTParser::readFromStream)

	// LENGTH + MAP + TEMPLATE + FIELDS . . .
	//Group = COUNT + MAP + TEMPLATEID
	//Yes, we can read without blocking

	int iret;
	
	if ( pSocketThreadData == NULL )
	{
		pSocketThreadData = new SocketThreadData*[m_totalSocketThreadCount];
		m_threadid        = new unsigned int*[m_totalSocketThreadCount];
		for (int i =0; i < m_totalSocketThreadCount; i++ )
		{
			if ( i == 0 )
			{
				m_threadid[i] = new unsigned int;
				*m_threadid[i] = 0;
				pSocketThreadData[i] = new SocketThreadData(*this, socket, addr);
				void *voidPtr = reinterpret_cast<void*> (pSocketThreadData[i]);
				if( !FIX::thread_spawn( &startSocketThread, voidPtr, *m_threadid[i] ) )
					throw FIX::RuntimeError("Unable to spawn thread-startSocketThread");
			}
		}
	}
	return;

	socklen_t addrlen = sizeof(addr);

	//while(true)
	{
		int size = recvfrom( socket, m_sockbuffer, sizeof(m_sockbuffer), 0, (struct sockaddr*)&addr, &addrlen );
		if ( size <= 0 )
		{
			if ( size == -1 ) return;
			throw SocketRecvFailed( size );
		}
			
			size -= 5;
		Locker l( m_iq_mutex );
		{
			m_iq.push_back(iMsg(m_sockbuffer+5, size)); //as per CME
			//iq.pop_front();
		}
			static char m_size[5] = {0};
			static unsigned int msgCount = 0;
			memset(m_size, 0,5);
			memcpy(m_size, m_sockbuffer,5);
			unsigned int newCount = atoi(m_size);
			if ( newCount - msgCount > 1)
			{
				std::cout << "Hard Limit :" << (newCount - msgCount) << "!" << newCount << " - " << msgCount << std::endl;
			}
			msgCount = newCount;
			if (m_BinLogFile.good())
			{

				m_BinLogFile.write((const char*)&size, sizeof(size));
				m_BinLogFile.write(m_sockbuffer+5, size);

			}
	}
	//if ( waitEnd - waitStart != 0 )
	//	printf("Lock Time ++++++++++++++++++= %d\n", waitEnd - waitStart);

	return;
	QF_STACK_POP
	}



	void FASTParser::readFromStream( int m_socket) throw ( SocketRecvFailed )
	{QF_STACK_PUSH(FASTParser::readFromStream)
	// LENGTH + MAP + TEMPLATE + FIELDS . . .
	//Group = COUNT + MAP + TEMPLATEID
	//Yes, we can read without blocking
	if (m_bufferSizeYetToRead == 0)
	{
		while ( m_lenSizeYetToRead < 5 )
		{
			int size = recv( m_socket, m_sockbuffer + m_lenSizeYetToRead, 1, 0 );
			//fprintf(stdout, m_sockbuffer + m_lenSizeYetToRead, size );
			if ( size <= 0 )
			{
				if ( size == -1 ) return;
				throw SocketRecvFailed( size );
			}
			if ((unsigned char)m_sockbuffer[m_lenSizeYetToRead] >= STOP_BIT)
			{
				m_sockbuffer[m_lenSizeYetToRead] &= VALUE_BIT;
				m_lenSizeYetToRead++;
				break;
			}
			m_lenSizeYetToRead++;
		}
		if ( m_lenSizeYetToRead > 4 )
			throw "Overlong for the message length";

		m_bufferSize = 0 - ((m_sockbuffer [0] & 0x00) != 0);

		for (int icnt = 0; icnt < m_lenSizeYetToRead; icnt ++)
			m_bufferSize = m_bufferSizeYetToRead = (m_bufferSizeYetToRead << 7) | m_sockbuffer [icnt];
		m_lenSizeYetToRead = 0;
	}

	if ( m_bufferSizeYetToRead )
	{
		int size = recv( m_socket, m_sockbuffer + m_bufferSize - m_bufferSizeYetToRead, m_bufferSizeYetToRead, 0 );
		if ( size <= 0 )
		{
			if ( size == -1 ) return;
			throw SocketRecvFailed( size );
		}
		if ( size == m_bufferSizeYetToRead )
		{
			Locker l( m_iq_mutex );
			{
				m_iq.push_back(iMsg(m_sockbuffer, m_bufferSizeYetToRead ));
			}
			m_bufferSizeYetToRead = 0;
		}
		else
		{
			m_bufferSizeYetToRead -= size;
		}
	}
	return;
	QF_STACK_POP
	}

	void FASTParser::writeMessage( const std::string& str ) throw ( MessageParseError )
	{
		FIX::Message msg(str, *m_dataDictionary, true);
		if (oFast.encode_message (eFAST_BASE_TID) < 0)
			return;

		oFast.reset_presence_map();
		FIX::MsgType msgType;
		msg.getHeader().getField( msgType );
		if ( strchr( "", msgType.getValue().c_str() [ 0 ] ) )
		{
			throw "MsgType is missing";
		}

		Msg2TemplateId::iterator ii = m_Message2TemplateId->find(msgType);
		if ( ii == m_Message2TemplateId->end())
			throw "Error, please define templateID";

		int tid = ii->second;
		oFast.encode_u32 (eFAST_MSG_TYPE, tid);
		FastTagVector tags = m_dataDictionary->getFieldTag( tid );

		if ( tid != 16002 && tid != 16003) //Hello Message
		{
			//encodeTags( eFAST_HDR_TEMPLATE, tagvalues );
		}

		encodeTags( tid, msg );

		if ( tid != 16002 && tid != 16003) //Hello Message
		{
			//encodeTags( eFAST_TRL_TEMPLATE, tagvalues );
		}

		if (oFast.encode_message_end (eFAST_BASE_TID) < 0)
			return;
		char* pbuffer = NULL;
		unsigned int iMsgLen = 0;
		oFast.get_codec_output(reinterpret_cast<u8**>(&pbuffer), &iMsgLen );
		iMsg message( pbuffer, (size_t)iMsgLen );
		m_sendQueue.push_back( message );

	}

	bool FASTParser::writeToStream( int m_socket, const sockaddr_in &addr) throw ( SocketRecvFailed )
	{
		const iMsg& msg = m_sendQueue.front();
		unsigned char pSize[5];
		int iStartPos = oFast.decode_message_length (eFAST_MSG_LEN, msg.length(), pSize);
		if (m_sendLength == 0)
		{
			int hdr = sendto( m_socket, reinterpret_cast<char*>(pSize), iStartPos, 0,(const struct sockaddr*) &addr, sizeof(addr) );
		}
		int result = sendto
			( m_socket, msg.c_str() + m_sendLength, msg.length() - m_sendLength, 0, (const struct sockaddr*)&addr, sizeof(addr) );

		if( result > 0 )
			m_sendLength += result;

		if( m_sendLength == msg.length() )
		{
			m_sendLength = 0;
			m_sendQueue.pop_front();
		}
		return !m_sendQueue.size();
	}


	bool FASTParser::writeToStream( int m_socket) throw ( SocketRecvFailed )
	{
		const iMsg& msg = m_sendQueue.front();
		unsigned char pSize[5];
		int iStartPos = oFast.decode_message_length (eFAST_MSG_LEN, msg.length(), pSize);
		if (m_sendLength == 0)
		{
			int hdr = send ( m_socket, reinterpret_cast<char*>(pSize), iStartPos, 0 );
		}
		int result = send
			( m_socket, msg.c_str() + m_sendLength, msg.length() - m_sendLength, 0 );

		if( result > 0 )
			m_sendLength += result;

		if( m_sendLength == msg.length() )
		{
			m_sendLength = 0;
			m_sendQueue.pop_front();
		}
		return !m_sendQueue.size();
	}

	void FASTParser::encodeTags(int tid, const FIX::Message &msg, int groupCount)
	{
		FastTagVector tags = m_dataDictionary->getFieldTag( tid );
		u32 ku = 0;
		i32 k = 0;
		double d = 0;
		i64 k64 = 0;
		u64 ku64 = 0;
		u8 v[50];
		u8 *data;
		std::vector<std::string> KeyValue;

		FastTagVector::iterator ii = tags.begin();
		FastTagVector::iterator iiend = tags.end();

		for ( ; ii != iiend; ++ii )
		{
			if ( ii->m_num == 10 || ii->m_num == 9 || ii->m_num == 9999)
			{
				continue;
			}
			ii->m_value = "";
			bool isFieldSet = false;
			if ( groupCount < 0 )
			{
				if( msg.isHeaderField(ii->m_num) && msg.getHeader().isSetField(ii->m_num) )
				{
					ii->m_value = msg.getHeader().getField(ii->m_num);
					isFieldSet = true;
				}
				else if( msg.isTrailerField(ii->m_num) && msg.getTrailer().isSetField(ii->m_num) )
				{
					ii->m_value = msg.getTrailer().getField(ii->m_num);
					isFieldSet = true;
				}
				else if ( msg.isSetField( ii->m_num) )
				{
					ii->m_value = msg.getField(ii->m_num);
					isFieldSet = true;
				}
			}
			else
			{
				FIX::Group g( tid, 99);

				if ( msg.hasGroup( groupCount , tid ) )
				{
					msg.getGroup(groupCount + 1 , tid, g);
					if ( g.isSetField( ii->m_num) )
					{
						ii->m_value = g.getField(ii->m_num);
						isFieldSet = true;
					}
				}
			}

			if ( !isFieldSet )
			{
				oFast.set_presence_map_x (ii->m_tag, ii->m_type);//need to set map here
				continue;
			}
			memset(v, '0', sizeof(v));
			switch( ii->m_type )
			{
			case eFAST_TYPE_ASCII:
				data = reinterpret_cast<u8*>(const_cast<char*>(ii->m_value.c_str()));
				oFast.encode_string (ii->m_tag, data, (int) strnlen ((char*) data, ii->m_value.length()));
				break;
			case eFAST_TYPE_I32:
				k = atoi(ii->m_value.c_str());
				oFast.encode_i32 (ii->m_tag, k);
				break;
			case eFAST_TYPE_U32:
				ku = atoi(ii->m_value.c_str());
				oFast.encode_u32 (ii->m_tag, ku);
				break;
			case eFAST_TYPE_GROUP:
				ku = atoi(ii->m_value.c_str());
				oFast.encode_group_count (ii->m_tag, ku);
				if ( ku )
				{
					for ( unsigned int i = 0; i < ku; i++ )
					{
						FASTGroup group;
						oFast.backup_group(group);
						u32 templateID = 0;
						if ( ii->get_ref_tid() == "none" )
						{
							//oFast.encode_u32 ( eFAST_MSG_TYPE, atoi(ii->get_ref_tid().c_str()) );
						}
						else
						{
							templateID = atoi(ii->get_ref_tid().c_str());
							oFast.encode_u32 ( eFAST_MSG_TYPE, templateID );
						}
						encodeTags( ii->get_num(), msg, i );
						oFast.restore_group(group);
					}
				}
				break;
			case eFAST_TYPE_DECMIAL:
				d = atof(ii->m_value.c_str());
				oFast.encode_double(ii->m_tag, d);
				sprintf(reinterpret_cast<char*>(v), "%f\0", d );
				ii->m_value = reinterpret_cast<char*>(v);
				break;
			case eFAST_TYPE_UNICODE:
				data = reinterpret_cast<u8*>(const_cast<char*>(ii->m_value.c_str()));
				oFast.encode_string (ii->m_tag, data, (int) strnlen ((char*) data, ii->m_value.length()));
				break;
			case eFAST_TYPE_I64:
				k64 = atol(ii->m_value.c_str());
				oFast.encode_i64 (ii->m_tag, k64);
				break;
			case eFAST_TYPE_U64:
				ku64 = atol(ii->m_value.c_str());
				oFast.encode_u64 (ii->m_tag, ku64);
				break;
			default:
				break;
			}
		}
	}
	void FASTParser::encodeTags(int tid, std::map<int, std::string> tagvalues)
	{
		FastTagVector tags = m_dataDictionary->getFieldTag( tid );
		u32 ku = 0;
		i32 k = 0;
		double d = 0;
		i64 k64 = 0;
		u64 ku64 = 0;
		u8 v[50];
		u8 *data;
		std::vector<std::string> KeyValue;
		FastTagVector::iterator ii = tags.begin();
		FastTagVector::iterator iiend = tags.end();

		for ( ; ii != iiend; ++ii )
		{
			if ( ii->m_num == 10 || ii->m_num == 9 || ii->m_num == 9999)
			{
				continue;
			}
			std::map<int, std::string>::iterator i = tagvalues.find(ii->m_num);
			if ( i == tagvalues.end() )
			{
				oFast.set_presence_map_x (ii->m_tag, ii->m_type);//need to set map here
				continue;
			}
			else
			{
				ii->m_value = i->second;
			}
			memset(v, '0', sizeof(v));
			switch( ii->m_type )
			{
			case eFAST_TYPE_ASCII:
				data = reinterpret_cast<u8*>(const_cast<char*>(ii->m_value.c_str()));
				oFast.encode_string (ii->m_tag, data, (int) strnlen ((char*) data, ii->m_value.length()));
				break;
			case eFAST_TYPE_I32:
				k = atoi(ii->m_value.c_str());
				oFast.encode_i32 (ii->m_tag, k);
				break;
			case eFAST_TYPE_U32:
				ku = atoi(ii->m_value.c_str());
				oFast.encode_u32 (ii->m_tag, ku);
				break;
			case eFAST_TYPE_GROUP:
				ku = atoi(ii->m_value.c_str());
				oFast.encode_group_count (ii->m_tag, ku);
				if ( ku )
				{
					for (unsigned int i = 0; i < ku; i++ )
					{
						FASTGroup group;
						oFast.backup_group(group);
						u32 templateID = 0;
						if ( ii->get_ref_tid() == "none" )
						{
							//oFast.encode_u32 ( eFAST_MSG_TYPE, atoi(ii->get_ref_tid().c_str()) );
						}
						else
						{
							templateID = atoi(ii->get_ref_tid().c_str());
							oFast.encode_u32 ( eFAST_MSG_TYPE, templateID );
						}
						encodeTags( ii->get_num(), tagvalues );
						oFast.restore_group(group);
					}
				}
				break;
			case eFAST_TYPE_DECMIAL:
				d = atof(ii->m_value.c_str());
				oFast.encode_double(ii->m_tag, d);
				sprintf(reinterpret_cast<char*>(v), "%f\0", d );
				ii->m_value = reinterpret_cast<char*>(v);
				break;
			case eFAST_TYPE_UNICODE:
				data = reinterpret_cast<u8*>(const_cast<char*>(ii->m_value.c_str()));
				oFast.encode_string (ii->m_tag, data, (int) strnlen ((char*) data, ii->m_value.length()));
				break;
			case eFAST_TYPE_I64:
				k64 = atol(ii->m_value.c_str());
				oFast.encode_i64 (ii->m_tag, k64);
				break;
			case eFAST_TYPE_U64:
				ku64 = atol(ii->m_value.c_str());
				oFast.encode_u64 (ii->m_tag, ku64);
				break;
			default:
				break;
			}
		}
	}
	void FASTParser::reset( unsigned int tid )
	{

		m_dataDictionary->resetDictionary (iFast, oFast, tid);
	}

}
